package file;

import operator.Handler;
import operator.OUtil;
import pri.file.FOperator;
import common.Constant;
import common.Singleton;
import view.Main;
import vo.Mean;

import java.io.File;
import java.text.SimpleDateFormat;
import java.util.Date;

public class XDocOperator{
    /**
     * 添加已经存在的意象链（ xDOC 文件）
     */
    private OUtil outil;
    private Handler handler;
    private Main m;
    private File selectedXDoc;

    private String readLength = null, fileContent = null;

    private String version = "source";

    private static XDocOperator xDocOperator;
    private XDocOperator() {}
    public static XDocOperator getOperator() {
        if (xDocOperator == null) {
            xDocOperator = new XDocOperator();
            xDocOperator.outil = Singleton.oUtil();
            xDocOperator.handler = Singleton.handler();
            xDocOperator.m = Singleton.main();
        }
        return xDocOperator;
    }

    public void readXDoc() {
        Constant.usingXDoc = selectedXDoc = Singleton.fUtil().findFile("xDoc");
        m.initialData();

        if (selectedXDoc != null) {
            String fileLenRecord = FOperator.readOut(selectedXDoc, 10);
            StringBuilder toReadLength = new StringBuilder();
            int i = 0;
            for (; i < fileLenRecord.length(); i++) {
                if(fileLenRecord.charAt(i) == ' ')
                    break;
                toReadLength.append(fileLenRecord.charAt(i));
            }
            readLength = toReadLength.toString();
            resolveContextAndMeans(Integer.parseInt(toReadLength.toString()), i);
        }
    }

    private void resolveContextAndMeans(int toReadLength, int index) {

        // TODO remember to add a method read(File file, int from, int to) in FOperator
        // 文章 + 意象字符串
        fileContent = FOperator.readOut(selectedXDoc, toReadLength + index).substring(index+1);

        // 解析出文章
        for (index = 0; index < fileContent.length(); index++) {
            if (fileContent.charAt(index) == '¤') {
                // 初始化
                handler.setContext(fileContent.substring(0, index));
                handler.addNew();
                break;
            }
        }

        // 解析意象
        boolean main = true;
        StringBuilder temp = new StringBuilder();
        String text = "";
        Mean tempMean = null;
        int from = -1;
        for (; index < fileContent.length(); index++) {
            char c = fileContent.charAt(index);
            switch (c) {
                case '¤':// 主意象描述结束
                    text = temp.toString();
                    main = true;
                    temp = new StringBuilder();
                    break;
                case '√':// 版本号
                    version = temp.toString();
                    temp = new StringBuilder();
                    break;
                case '☆':// 副意象描述结束
                    text = temp.toString();
                    main = false;
                    temp = new StringBuilder();
                    break;
                case '∷':// 位置起始结束
                    from = Integer.parseInt(temp.toString());
                    temp = new StringBuilder();
                    break;
                case '※':// 位置结束
                    tempMean = operateMean(Integer.parseInt(temp.toString()), from, main, text, tempMean);
                    temp = new StringBuilder();
                    break;
                case '█':// 隐含位置
                    temp = new StringBuilder();
                    break;
                case '┓':// 初始化信息
                    String ps[] = temp.toString().split("：");

                    m.recordPage = m.presentPage = Integer.parseInt(ps[0]);
                    handler.getM().jtfPrePgPgSet(m.presentPage); // 设置当前所在页
                    handler.getText().setCaretPosition(m.recordCarePosition = Integer.parseInt(ps[1])); // 设置光标位置
                    // 设置实时保存 已删除

                    temp = new StringBuilder();
                    break;
                case '◎':// 属性结束
                    setMeanAttr(temp.toString(), tempMean);
                    temp = new StringBuilder();
                    break;
                default:
                    temp.append(c);
            }
        }

        afterResolve(tempMean);
    }

    private Mean operateMean(int loc, int from, boolean main, String text, Mean tempMean) {

        if (!text.equals("")) {// 不为空说明刚刚开始了新的意象读取
            if (tempMean != null) {
                tempMean.setDescription();// 上一个意象设置位置描述
            }
            if (main) {
                if (from != -1) {
                    tempMean = handler.getLocationInAll(text, from, loc);
                    Mean.turnToMain(tempMean);
                } else
                    tempMean = new Mean(text, loc, handler.getGroupId());
            } else {
                assert tempMean != null;
                if (from != -1) {
                    tempMean.addNext(handler.getLocationInAll(text, from, loc));
                }
                else {
                    tempMean.addNext(text, loc);
                }
                tempMean = tempMean.getNext();
            }
        } else {
            tempMean.setLocation(loc);
        }
        return tempMean;
    }

    private void setMeanAttr(String temp, Mean tempMean) {
        StringBuilder type = new StringBuilder();
        String str = "";
        boolean old = true;
        for (int x = 0; x < temp.length(); x++) {
            if (temp.charAt(x) == '┬') {
                str = type.toString();
                type = new StringBuilder();
                old = false; // compatibility model
            } else
                type.append(temp.charAt(x));
        }
        if (!old)
            tempMean.setPointedAttr(str, Integer.parseInt(type.toString()), version);
    }

    private void afterResolve(Mean tempMean) {
        if (tempMean != null)
            tempMean.setDescription();// 最后一个意象设置位置描述

        Singleton.vc().attr_addAll();
        for (Mean next : handler.mainMean) {
            while (next.getNext() != null) {
                next = next.getNext();
            }
        }
    }

    /**
     * 写入 xDoc 文件。 能保存源文件。
     */
    void writeXDOC(File usingXDoc) {
        if (usingXDoc == null)
            return;

        String fileName = usingXDoc.getName().split(".xDoc")[0];

        // 创建目录
        File backupFolder = new File(usingXDoc.getParent() + "/" + fileName + " BackUp");
        backupFolder.mkdirs();

        // 创建备份文件
        File backup = new File(backupFolder.getPath() + "/" + fileName +
                new SimpleDateFormat("yyyy-MM-dd hh-mm-ss").format(new Date()) + ".xDoc");

        // 写备份
        FOperator.write(backup, readLength + " " +fileContent, Constant.Encode);

        writeXDOCFile(usingXDoc);
        Constant.usingXDoc = usingXDoc;
    }

    /**
     * 写 XDoc
     */
    private void writeXDOCFile(File file) {
        StringBuilder toWrite = new StringBuilder();
        toWrite.append(outil.getTextExcepted13(handler.getContext())); // 写入文本
        toWrite.append("¤" + Constant.ATTR_VERSION + "√"); // 写入版本号

        for (Mean next : handler.mainMean) { // 写入意象
            toWrite.append(decompose(next, "¤"));
            while (next.getNext() != null) {
                next = next.getNext();
                toWrite.append(decompose(next, "☆"));
            }
        }

        toWrite = new StringBuilder(toWrite.length() + " " + toWrite + m.presentPage); // 长度及保存时的页面
        toWrite.append("：").append(handler.getText().getCaretPosition()); // 退出时页面光标位置
        toWrite.append("：" + 1 + "┓"); // 是否实时保存

        FOperator.write(file, toWrite.toString(), Constant.Encode);
        handler.modifySaved();
    }

    /**
     * 将 Mean 装换成要在 XDoc 中记录的字符串
     */
    private String decompose(Mean mean, String sign) {
        StringBuilder toWhite = new StringBuilder();
        toWhite.append(mean.getText()).append(sign);
        toWhite.append(mean.getLocation()).append('※');
        String attributes[] = mean.getAttributes();
        for (int i = 0; i < attributes.length; i++) {
            if (!attributes[i].equals(""))
                toWhite.append(attributes[i]).append("┬").append(i + 1).append("◎");
        }
        return toWhite.toString();
    }
}
